package com.lexi.common.poi.excel;

import com.lexi.common.poi.model.ExcelTableModel;
import lombok.Cleanup;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.BorderStyle;
import org.apache.poi.ss.usermodel.FillPatternType;
import org.apache.poi.xssf.usermodel.*;

import java.io.FileInputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Slf4j
public class ExcelUtils {
    public final static Short defaultStyleKey=0;
    private Integer headerStartRow=0;
    private boolean headerType=true;
    private Integer startRow=1;
    private Map<Short,XSSFCellStyle> colorMap=new HashMap<Short,XSSFCellStyle>();

    /**
     * 按行写入
     * @param out
     * @param filePath
     * @param hearderList
     * @param startHeader
     * @param dataList
     * @param voList
     * @param startRow
     * @param startCol
     * @param styleFlag
     * @param <T>
     */
    public <T> void exportExcel(OutputStream out,String filePath, List<String[]> hearderList, Integer startHeader, List<T> dataList, List<ExcelTableModel> voList, int startRow, int startCol, boolean styleFlag){
        @Cleanup
        XSSFWorkbook wb=null;
        try{
            wb=getWorkbook(filePath);
            XSSFSheet sheet = getSheet(wb,0);
            //设置Header
            setHeader(hearderList,startHeader,sheet);
            //设置Body
            setBody(dataList,voList,startRow,startCol,sheet,styleFlag);
            wb.write(out);
        }catch (Exception e){
            log.error("Excel Error",e);
        }
    }

    /**
     * 按列写入
     * @param out
     * @param filePath
     * @param hearderList
     * @param startHeader
     * @param dataList
     * @param voList
     * @param startRow
     * @param startCol
     * @param styleFlag
     * @param <T>
     */
    public <T> void exportExcelByTranspose(OutputStream out,String filePath, List<String[]> hearderList, Integer startHeader, List<T> dataList, List<ExcelTableModel> voList, int startRow, int startCol, boolean styleFlag){
        @Cleanup
        XSSFWorkbook wb=null;
        try{
            wb=getWorkbook(filePath);
            XSSFSheet sheet = getSheet(wb,0);
            //设置Header
            setHeader(hearderList,startHeader,sheet);
            //设置Body
            setBody(sheet,dataList,voList,startRow,startCol,styleFlag);
            wb.write(out);
        }catch (Exception e){
            log.error("Excel Error",e);
        }
    }

    /**
     * 按行生成数据部分
     * @param dataList
     * @param modelList
     * @param startRow
     * @param startCol
     * @param sheet
     * @param styleFlag
     * @param <T>
     */
    @SneakyThrows
    private <T> void setBody(List<T> dataList, List<ExcelTableModel> modelList, int startRow, int startCol, XSSFSheet sheet, boolean styleFlag) {
        if(null!=dataList){
            for(int i =0;i<dataList.size();i++){
                XSSFRow curRow=getRow(sheet,startRow+i);
                T t=dataList.get(i);
                if(t==null){
                    continue;
                }
                for(int j=0;j<modelList.size();j++){
                    ExcelTableModel model=modelList.get(j);
                    XSSFCell curCell=getCell(curRow,startCol+j);
                    Object objValue=t.getClass().getDeclaredMethod(model.getAttName()).invoke(t);
                    setCellValue(model,objValue,curCell);
                    if(styleFlag){
                        setCellStyle(model.getDataColor(),curCell);
                    }
                }
            }
        }
    }

    /**
     * 案列写入 数据部分
     * @param dataList
     * @param modelList
     * @param startRow
     * @param startCol
     * @param sheet
     * @param styleFlag
     * @param <T>
     */
    @SneakyThrows
    private <T> void setBody(XSSFSheet sheet,List<T> dataList, List<ExcelTableModel> modelList, int startRow, int startCol, boolean styleFlag) {
        if(null!=dataList){
            for(int j=0;j<modelList.size();j++){
                ExcelTableModel model=modelList.get(j);
                XSSFRow curRow=getRow(sheet,startRow+j);
                for(int i =0;i<dataList.size();i++){
                    T t=dataList.get(i);
                    if(t==null){
                        continue;
                    }
                    XSSFCell curCell=getCell(curRow,startCol+i);
                    Object objValue=t.getClass().getDeclaredMethod(model.getAttName()).invoke(t);
                    setCellValue(model,objValue,curCell);

                    if(styleFlag){
                        setCellStyle(model.getDataColor(),curCell);
                    }
                }
            }
        }
    }
    /**
     * 设置样式
     * @param color
     * @param cell
     */
    private void setCellStyle(Short color, XSSFCell cell) {
        XSSFCellStyle defaultStyle=getDefaultCellStyle(cell.getSheet().getWorkbook());
        if(color!=null){
            XSSFCellStyle styleTemp=colorMap.get(color);
            if(styleTemp==null){
                styleTemp=cell.getSheet().getWorkbook().createCellStyle();
                styleTemp.cloneStyleFrom(defaultStyle);
                styleTemp.setFillForegroundColor(color);
                styleTemp.setFillPattern(FillPatternType.SOLID_FOREGROUND);
                colorMap.put(color,styleTemp);
            }
            cell.setCellStyle(styleTemp);
        }else{
            cell.setCellStyle(defaultStyle);
        }
    }

    /**
     * 设置单元格值
     * @param model
     * @param value
     * @param cell
     */
    private void setCellValue(ExcelTableModel model, Object value, XSSFCell cell) {
        if(value==null){

        }else{
            cell.setCellValue(value.toString());
        }
    }

    /**
     * 获取单元格
     * @param row
     * @param cellIndex
     * @return
     */
    private XSSFCell getCell(XSSFRow row, int cellIndex) {
        XSSFCell curCell=row.getCell(cellIndex);
        if(curCell==null){
            curCell=row.createCell(cellIndex);
        }
        return curCell;
    }

    /**
     * 获取行
     * @param sheet
     * @param rowIndex
     * @return
     */
    private XSSFRow getRow(XSSFSheet sheet, int rowIndex) {
        XSSFRow row=sheet.getRow(rowIndex);
        if(row==null){
            row=sheet.createRow(rowIndex);
        }
        return row;
    }

    /**
     * 设置表头
     * @param hearderList
     * @param startHeader
     * @param sheet
     */
    private void setHeader(List<String[]> hearderList, Integer startHeader, XSSFSheet sheet) {
        if(null!=hearderList){
            for(int i=0;i<hearderList.size();i++){
                String[] formHeader=hearderList.get(i);
                XSSFRow row=sheet.createRow(startHeader+i);
                for(int j=0;i<formHeader.length;j++){
                    String header=formHeader[j];
                    XSSFCell cell=row.createCell(j+1);
                    cell.setCellValue(header);
                    cell.setCellStyle(colorMap.get(defaultStyleKey));
                }
            }
        }
    }

    /**
     * 获取工作表Sheet
     * @param wb
     * @param index
     * @return
     */
    private XSSFSheet getSheet(XSSFWorkbook wb, int index) {
        XSSFSheet sheet=null;
        if(wb.getNumberOfSheets()==0){
            sheet=wb.createSheet("Sheet1");
        }else if(wb.getNumberOfSheets()>0 && index<wb.getNumberOfSheets()){
            sheet=wb.getSheetAt(index);
        }else{
            sheet=wb.createSheet();
        }
        return sheet;
    }

    /**
     * 获取工作簿 Workbook
     * @param filePath
     * @return
     */
    @SneakyThrows
    private  XSSFWorkbook getWorkbook(String filePath) {
        XSSFWorkbook wb=null;
        if(StringUtils.isNotEmpty(filePath)){
            InputStream inputStream=getPathResource(filePath);
            wb=new XSSFWorkbook((inputStream));
        }else{
            wb=new XSSFWorkbook();
        }
        getDefaultCellStyle(wb);
        return wb;
    }

    /**
     * 获取单元格样式
     * @param wb
     * @return
     */
    private  XSSFCellStyle getDefaultCellStyle(XSSFWorkbook wb) {
        XSSFCellStyle defaultCellStyle=colorMap.get(defaultStyleKey);
        if(defaultCellStyle!=null){
            return defaultCellStyle;
        }
        defaultCellStyle= wb.createCellStyle();
        defaultCellStyle.setBorderBottom(BorderStyle.THIN);
        defaultCellStyle.setBorderTop(BorderStyle.THIN);
        defaultCellStyle.setBorderLeft(BorderStyle.THIN);
        defaultCellStyle.setBorderRight(BorderStyle.THIN);
        colorMap.put(defaultStyleKey,defaultCellStyle);
        return defaultCellStyle;

    }

    /**
     * 获取文件输入流
     * @param filePath
     * @return
     */
    @SneakyThrows
    private  InputStream getPathResource(String filePath) {
//        for Springboot
//        ClassPathResource res=new ClassPathResource(filePath);
//        return res.getInputStream();
        return new FileInputStream(filePath);
    }

}
